package com.telit.firecommand.service.impl;

import cn.hutool.core.date.BetweenFormater;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.github.xiaolyuh.annotation.CacheEvict;
import com.github.xiaolyuh.annotation.Cacheable;
import com.telit.common.constant.MsgIdentificationConstants;
import com.telit.common.entity.DataReturn;
import com.telit.common.exception.ForestBaseException;
import com.telit.common.vo.user.SysUserDetailVo;
import com.telit.communicate.dto.SendMessageDTO;
import com.telit.communicate.feign.RemoteCommunicateService;
import com.telit.firecommand.dao.CommCommunicateRecordDao;
import com.telit.firecommand.dto.CommunicateRecordDTO;
import com.telit.firecommand.entity.CommCommunicateRecord;
import com.telit.firecommand.service.UserInfoService;
import com.telit.upms.vo.MicroSysUserAllInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @Auther amy
 * @Describe 融合通讯业务层
 */
@Service
@Slf4j
public class CommunicateRecordService extends ServiceImpl<CommCommunicateRecordDao, CommCommunicateRecord> {

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private RemoteCommunicateService communicateFeignClient;

    /**
     * 融合通讯列表
     *
     * @param fireId
     *
     * @return
     */
    public List<CommCommunicateRecord> listByFireId(String fireId) {
        //2022-05-18 优化 避免过度请求 -------fixed by yzx-------start
        /*QueryWrapper<CommCommunicateRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("fire_id", fireId);
        List<CommCommunicateRecord> list = baseMapper.selectList(queryWrapper);

        if (!CollectionUtils.isEmpty(list)) {
            list.forEach(commCommunicateRecord -> {
                // 将参会人用逗号隔开
                commCommunicateRecord.setParticipants(commCommunicateRecord.getParticipants() == null ? null :
                        StringUtils.join(JSON.parseArray(commCommunicateRecord.getParticipants(), String.class), ","));
                // 将通讯时长转成时分秒
                String timeDuration = DateUtil.formatBetween(commCommunicateRecord.getEndTime(), commCommunicateRecord.getStartTime(), BetweenFormater.Level.SECOND);
                commCommunicateRecord.setMeetingDuration(timeDuration);
                SysUserDetailVo sysUserDetailVo = userInfoService.getUserInfo(commCommunicateRecord.getSponsor());
                commCommunicateRecord.setSponsorName(sysUserDetailVo == null ? null : sysUserDetailVo.getRealName());
            });
        }
        return list;*/
        QueryWrapper<CommCommunicateRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("fire_id", fireId);
        List<CommCommunicateRecord> list = baseMapper.selectList(queryWrapper);
        final Map<Long, String> idNameMapping = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(list)) {
            final List<Long> ids = list.parallelStream().map(CommCommunicateRecord::getSponsor).collect(
                    Collectors.toList());
            idNameMapping.putAll(userInfoService.findAndConvertUserInfoByIds(ids));
            list.forEach(commCommunicateRecord -> {
                // 将参会人用逗号隔开
                commCommunicateRecord.setParticipants(commCommunicateRecord.getParticipants() == null ? null :
                        StringUtils.join(JSON.parseArray(commCommunicateRecord.getParticipants(), String.class), ","));
                // 将通讯时长转成时分秒
                //查看代码bug存在结束时间为null的情况，对原代码进行非空判断，另有一处也存在这个情况
                if (commCommunicateRecord.getEndTime() != null && commCommunicateRecord.getStartTime() != null) {
                    String timeDuration = DateUtil.formatBetween(commCommunicateRecord.getEndTime(),
                            commCommunicateRecord.getStartTime(), BetweenFormater.Level.SECOND);
                    commCommunicateRecord.setMeetingDuration(timeDuration);
                }
                commCommunicateRecord.setSponsorName(
                        ObjectUtil.defaultIfNull(idNameMapping.get(commCommunicateRecord.getSponsor()), StrUtil.EMPTY));
            });
        }
        return list;
        //2022-05-18 优化 避免过度请求 -------fixed by yzx-------end
    }

    /**
     * 查询火情最后一次通话记录
     *
     * @return
     */
    @Cacheable(value = "firecommand:communicate:latestRecordByFireId", depict = "查询火情最后一次通话记录", key = "#p0")
    public CommunicateRecordDTO latestRecordByFireId(String fireId) {
        /*List<CommCommunicateRecord> list = baseMapper.latestByFireId(fireId);
        if (!CollectionUtils.isEmpty(list)) {
            // 结束时间等于null,说明通话未结束
            if (list.get(0).getEndTime() == null) {
                CommCommunicateRecord record = list.get(0);
                // 设置当前参会人数
                CommunicateRecordDTO dto = new CommunicateRecordDTO();
                BeanUtils.copyProperties(record, dto);
                String currentParticipants = record.getCurrentParticipants();
                dto.setCurrentPersonCount(getCurrentCount(currentParticipants));

                // 会议发起人名称
                SysUserDetailVo vo = userInfoService.getUserInfo(dto.getSponsor());
                if (vo != null) {
                    dto.setSponsorName(vo.getRealName());
                }
                return dto;
            }
        }*/
        //以上会返回多条不需要的数据，先对以上功能进行优化如下：
        CommCommunicateRecord commCommunicateRecord = baseMapper.latestOneByFireId(fireId);
        if (ObjectUtil.isNotEmpty(commCommunicateRecord)) {
            // 设置当前参会人数
            CommunicateRecordDTO dto = new CommunicateRecordDTO();
            BeanUtils.copyProperties(commCommunicateRecord, dto);
            // TODO 结束时间等于null,说明通话未结束，此判断目前不知道存在的意义，暂时注释
//            if (commCommunicateRecord.getEndTime() == null) {
            String currentParticipants = commCommunicateRecord.getCurrentParticipants();
            dto.setCurrentPersonCount(getCurrentCount(currentParticipants));

            //对于发起人ID做非空和非零判断
            if (dto.getSponsor() != null && dto.getSponsor() != 0L) {
                // 会议发起人名称
                MicroSysUserAllInfoVo vo = userInfoService.getUserInfo(dto.getSponsor());
                if (ObjectUtil.isNotEmpty(vo) && StrUtil.isNotEmpty(vo.getRealName())) {
                    dto.setSponsorName(vo.getRealName());
                }
            }

//            }
            return dto;
        }
        return null;
    }

    /**
     * 设置参会人数
     *
     * @return
     */
    private int getCurrentCount(String currentParticipants) {

        if (org.springframework.util.StringUtils.hasText(currentParticipants)) {
            List<String> json = JSON.parseArray(currentParticipants, String.class);
            if (!CollectionUtils.isEmpty(json)) {
                return json.size();
            }
        }
        return 0;
    }

    /**
     * 新增通讯信息
     *
     * @param commCommunicateRecord
     *
     * @return
     */
    @CacheEvict(value = "firecommand:communicate:latestRecordByFireId", key = "#p0.fireId")
    public Long add(CommCommunicateRecord commCommunicateRecord) {
        // 判断该房间号是否存在,如果存在就不进行记录
        QueryWrapper<CommCommunicateRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("channel", commCommunicateRecord.getChannel());
        CommCommunicateRecord record = baseMapper.selectOne(wrapper);
        if (record != null) {
            log.info("音视频通话房间已经存在,channel:{}", commCommunicateRecord.getChannel());
            return record.getId();
        }

        commCommunicateRecord.setStartTime(new Date());
        List<String> list = new ArrayList<>();
        list.add(String.valueOf(commCommunicateRecord.getSponsor()));
        // 当前参会人员
        commCommunicateRecord.setCurrentParticipants(JSONObject.toJSONString(list));
        if (baseMapper.insert(commCommunicateRecord) <= 0) {
            throw new ForestBaseException("新增融合通讯信息失败");
        }

        // 推送websocket,刷新通话回溯列表
        communicateFeignClient.sendMsg(new SendMessageDTO("web",
                JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.REFRESH_MEETING_LOG, "刷新通话列表"))));

        // 将记录id返回前端
        return commCommunicateRecord.getId();
    }

    /**
     * 更新通讯信息
     *
     * @param dto
     *
     * @return
     */
    @CacheEvict(value = "firecommand:communicate:latestRecordByFireId", allEntries = true)
    public int update(CommunicateRecordDTO dto) {
        CommCommunicateRecord commCommunicate = baseMapper.selectById(dto.getId());
        if (commCommunicate == null) {
            throw new ForestBaseException("该通话回溯不存在");
        }

        CommCommunicateRecord commCommunicateRecord = new CommCommunicateRecord();
        BeanUtils.copyProperties(dto, commCommunicateRecord);
        Set<String> newParticipants = dto.getParticipantList();

        if (!CollectionUtils.isEmpty(newParticipants)) {
            commCommunicateRecord.setParticipants(JSON.toJSONString(newParticipants));
        }
        return baseMapper.updateById(commCommunicateRecord);
    }

    /**
     * 添加会议成员，记录参会人员
     *
     * @return
     */
    @CacheEvict(value = "firecommand:communicate:latestRecordByFireId", allEntries = true)
    public int addMember(CommunicateRecordDTO communicateRecordDTO) {
        CommCommunicateRecord commCommunicate = baseMapper.selectById(communicateRecordDTO.getId());
        if (commCommunicate == null) {
            throw new ForestBaseException("该通话回溯不存在");
        }

        Set<String> nameList = communicateRecordDTO.getParticipantList();
        if (!CollectionUtils.isEmpty(nameList)) {
            if (StringUtils.isNotBlank(commCommunicate.getParticipants())) {
                List<String> oldParticipants = JSON.parseArray(commCommunicate.getParticipants(), String.class);
                nameList.addAll(oldParticipants);
            }
            // 将合并后的参会人员重新入库
            commCommunicate.setParticipants(JSON.toJSONString(nameList));
        }

        // 结束时间不为空，说明通话结束
        if (communicateRecordDTO.getEndTime() != null) {
            UpdateWrapper<CommCommunicateRecord> wrapper = new UpdateWrapper();
            wrapper.eq("id", commCommunicate.getId());
            wrapper.set("end_time", communicateRecordDTO.getEndTime());
            wrapper.set("meeting_duration", communicateRecordDTO.getMeetingDuration());
            wrapper.set("current_participants", null);

            // 推送websocket,刷新通话回溯列表
            communicateFeignClient.sendMsg(new SendMessageDTO("web",
                    JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.REFRESH_MEETING_LOG, "刷新通话列表"))));
            return baseMapper.update(null, wrapper);
        }

        // 推送websocket,刷新通话回溯列表
        communicateFeignClient.sendMsg(new SendMessageDTO("web",
                JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.REFRESH_MEETING_LOG, "刷新通话列表"))));

        return baseMapper.updateById(commCommunicate);
    }

    /**
     * 完成会议（用于websocket异常断开）
     *
     * @return
     */
    public int finishMeeting(CommCommunicateRecord record) {
        if (record != null) {
            // 封装参数
            UpdateWrapper<CommCommunicateRecord> wrapper = new UpdateWrapper<>();
            wrapper.eq("id", record.getId());

            Date endTime = new Date();
            wrapper.set("end_time", endTime);
            //--由于存在FireCommandMessageProcessController异常中断的情况，在获取end_time为null，日志中存在报“空指针”异常，在以下代码中把结束时间设置如record，设置开始
            if (ObjectUtil.isEmpty(record.getEndTime())) {
                record.setEndTime(endTime);
            }
            //--设置结束如上
            wrapper.set("meeting_duration",
                    String.valueOf(record.getStartTime().getTime() - record.getEndTime().getTime() / 1000));
            wrapper.set("current_participants", null);
            return baseMapper.update(null, wrapper);
        }
        return 0;
    }

    /**
     * 查询会议发起人最后一次正在通话的记录(证明是否有未完成的通话并是房主)
     *
     * @param sponsor
     *
     * @return
     */
    public CommCommunicateRecord listBySponsor(Long sponsor) {
        List<CommCommunicateRecord> records = baseMapper.listBySponsor(sponsor);
        if (!CollectionUtils.isEmpty(records)) {
            return records.get(0);
        }
        return null;
    }

    /**
     * 根据火情id查询是否存在音视频通话
     *
     * @return
     */
    public boolean checkHasMeetingByFireId(Long fireId) {
        List<CommCommunicateRecord> list = baseMapper.latestByFireId(fireId);
        // 没有通话记录
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        // 有通话记录,但是最近一次记录未完成
        CommCommunicateRecord record = list.get(0);
        if (record.getEndTime() == null) {
            return true;
        }
        return false;
    }

}
